package com.aloha.springframework.aop.aspectj.annotation;

import com.aloha.springframework.aop.Advisor;
import com.aloha.springframework.aop.aspectj.*;
import com.aloha.springframework.beans.BeansException;
import com.aloha.springframework.beans.factory.BeanFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author DaiZhiHeng
 * @description 为AOP创建代理
 * @date 2023/8/2 18:00
 */
public class ReflectiveAspectJAdvisorFactory implements AspectJAdvisorFactory {

    private BeanFactory beanFactory;

    @Override
    public boolean isAspect(Class<?> clazz) {
        return clazz.isAnnotationPresent(Aspect.class);
    }

    @Override
    public List<Advisor> getAdvisors(Class<?> clazz) {
        AspectInstanceFactory instanceFactory = new SingletonAspectInstanceFactory(beanFactory.getBean(clazz));
        List<Advisor> advisors = new ArrayList<>();
        for (Method method : clazz.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Around.class)) {
                if (method.getParameterCount() == 0) {
                    throw new IllegalStateException("环绕通知的参数中缺少 ProceedingJoinPoint");
                }
                if (!ProceedingJoinPoint.class.equals(method.getParameterTypes()[0])) {
                    throw new IllegalStateException("环绕通知的参数中第一个位置必须是 ProceedingJoinPoint");
                }
                Around around = method.getAnnotation(Around.class);
                AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
                advisor.setExpression(around.value());
                advisor.setAdvice(new AspectJAroundAdvice(method, instanceFactory));
                advisors.add(advisor);
            }
        }
        return advisors;
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}
